package com.itany.manager.exception;

import com.itany.manager.response.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.stream.Collectors;

/**
 * 全局异常处理器，用于统一拦截并处理 Controller 层抛出的异常。
 * 返回结构化的错误信息（ApiResponse），避免直接暴露异常堆栈给客户端。
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理自定义业务异常（如 ServiceException）
     * 适用场景：
     * - 业务逻辑校验失败（如 "用户不存在"、"订单已支付"）
     * - 权限不足（如 "无访问权限"）
     * 返回 HTTP 400 (Bad Request)，并携带具体的错误信息。
     */
    @ExceptionHandler(ServiceException.class)
    public ApiResponse<?> handleServiceException(ServiceException e) {
        log.error("业务异常: {}", e.getMessage(), e);
        return ApiResponse.error(400, e.getMessage());
    }

    /**
     * 处理参数校验异常（@Valid 触发的 MethodArgumentNotValidException）
     * 适用场景：
     * - 使用 @Valid 注解校验 DTO 参数时，如果校验失败（如字段为空、格式错误）
     * 返回 HTTP 400 (Bad Request)，并拼接所有字段的错误信息。
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<?> handleValidationException(MethodArgumentNotValidException ex) {
        String message = ex.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.joining("; "));
        log.warn("参数校验失败: {}", message);
        return ApiResponse.error(400, message);
    }

    /**
     * 处理参数类型不匹配异常（如期望 Integer 但传入 String）
     * 适用场景：
     * - URL 参数或 @RequestParam 类型转换失败（如 "/user?id=abc"，但 id 需要数字）
     * - @PathVariable 类型不匹配
     * 返回 HTTP 400 (Bad Request)，并提示期望的类型。
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ApiResponse<?> handleTypeMismatch(MethodArgumentTypeMismatchException ex) {
        String message = String.format("参数 '%s' 类型错误，需要 %s 类型",
                ex.getName(),
                ex.getRequiredType() != null ? ex.getRequiredType().getSimpleName() : "未知");
        log.warn("参数类型错误: {}", message);
        return ApiResponse.error(400, message);
    }

    /**
     * 处理运行时异常（如 NullPointerException、IllegalArgumentException）
     * 适用场景：
     * - 代码逻辑错误（如空指针、数组越界）
     * - 非预期的运行时错误
     * 返回 HTTP 500 (Internal Server Error)，避免暴露内部细节。
     */
    @ExceptionHandler(RuntimeException.class)
    public ApiResponse<?> handleRuntimeException(RuntimeException e) {
        log.error("系统运行时异常", e);
        return ApiResponse.error(500, "系统繁忙，请稍后重试");
    }

    /**
     * 兜底处理所有其他未被捕获的异常
     * 适用场景：
     * - 未预料到的异常（如数据库连接失败、第三方服务调用异常）
     * 返回 HTTP 500 (Internal Server Error)，避免暴露内部细节。
     */
    @ExceptionHandler(Exception.class)
    public ApiResponse<?> handleException(Exception e) {
        log.error("系统未知异常", e);
        return ApiResponse.error(500, "系统繁忙，请稍后重试");
    }
}